package com.huajx.mina.tcpserver.acceptor;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;

import com.huajx.util.ObjectUtil;
import org.apache.mina.core.service.IoAcceptor;
import org.apache.mina.core.service.IoHandler;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.filter.codec.ProtocolCodecFactory;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.executor.ExecutorFilter;
import org.apache.mina.filter.keepalive.KeepAliveFilter;
import org.apache.mina.filter.keepalive.KeepAliveMessageFactory;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public abstract class AbstractNioSocketAcceptor {
	protected static Logger logger = LoggerFactory.getLogger(AbstractNioSocketAcceptor.class);
	
	protected IoAcceptor acceptor;
	protected IoHandler ioHandler;
	protected int[] ports;

	/**
	 * 服务运行状态：服务是否正在运行
	 */
	protected boolean serverRunning = false;

//	ProtocolCodecFactory codecFactory;

	KeepAliveMessageFactory kamf;
	
	protected abstract ProtocolCodecFactory getCoderFactory();

	/**
	 * 设置 I/O 处理器。 该 I/O 处理器会负责处理该 I/O 服务所管理的所有 I/O 会话产生的 I/O 事件。
	 * 
	 * @param ioHandler
	 */
	public void setIoHandler(IoHandler ioHandler) {
		this.ioHandler = ioHandler;
	}

	/**
	 * 创建bind()方法接收连接
	 * 
	 * @throws IOException
	 */
	public void bind() throws IOException {
		if (serverRunning) {
			return;
		}
		
		if (ObjectUtil.isEmpty(ports)) {
			logger.info("服务端启动失败，未设置端口"); // 测试使用
		}
		
		// 创建 协议编码解码过滤器ProtocolCodecFilter
		// 设置序列化Object 可以自行设置自定义解码器
		ProtocolCodecFilter pf = new ProtocolCodecFilter(getCoderFactory());
		
		// getFilterChain() 获取 I/O 过滤器链，可以对 I/O 过滤器进行管理，包括添加和删除 I/O 过滤器。
		acceptor = new NioSocketAcceptor();
		
		// // 设置缓存大小
		// acceptor.getSessionConfig().setReadBufferSize(1024);

		// 设置过滤器
		
		// 线程池
		acceptor.getFilterChain().addLast("executor", new ExecutorFilter(Executors.newCachedThreadPool()));
		
		// 日志
		// acceptor.getFilterChain().addLast("logger", new LoggingFilter());
		
		// 协议处理 
		acceptor.getFilterChain().addLast("codec", pf);
		
		if(kamf != null){
			KeepAliveFilter kaf = new KeepAliveFilter(kamf, IdleStatus.BOTH_IDLE);
			kaf.setForwardEvent(true);
			kaf.setRequestInterval(30); // 本服务器为被定型心跳 即需要每30秒接受一个心跳请求 否则该连接进入空闲状态
			// 并且发出idled方法回调
			acceptor.getFilterChain().addLast("heart", kaf);
		}

		// 读写通道60秒内无操作进入空闲状态
		acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 6000);
		// 绑定逻辑处理器
		acceptor.setHandler(ioHandler);

		List<SocketAddress> socketAddresses = new ArrayList<>();

		StringBuilder sb = new StringBuilder();
		for (int port : ports) {
			socketAddresses.add(new InetSocketAddress(port));
			sb.append(port).append(", ");
		}

		// 绑定端口
		acceptor.bind(socketAddresses);

		logger.info("服务端启动成功...端口号为:" + sb.toString()); // 测试使用

		serverRunning = true;
	}

	/**
	 * 创建unbind()方法停止监听
	 */
	public void unbind() {
		if (!serverRunning || acceptor == null) {
			serverRunning = false;
			return;
		}
		
		acceptor.unbind();
		acceptor.dispose();

		logger.info("服务端停止成功");

		serverRunning = false;
	}

	/**
	 * 设置端口
	 * 
	 * @param ports
	 */
	public void setPorts(int... ports) {
		this.ports = ports;
	}

	public void setKamf(KeepAliveMessageFactory kamf) {
		this.kamf = kamf;
	}

	public boolean isServerRunning() {
		return serverRunning;
	}
}
